﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using HBCONTROLMODLib;
using System.Text.RegularExpressions;
using System.Configuration;
using Microsoft.Win32;

namespace HouseBotScreensaver
{

    enum FadeType
    {
        FadeIn,
        FadeOut
    }

    public partial class ScreensaverForm : Form
    {
        bool IsPreviewMode;
        const int RETRY = 3;
        HBControl hb;

        int hbPort = Properties.Settings.Default.HouseBotPort;
        string hbHost = Properties.Settings.Default.HouseBotHost;
        string hbPassword = Properties.Settings.Default.HouseBotPassword;
        string label1TextTemplate = Properties.Settings.Default.Label1Text;
        string label2TextTemplate = Properties.Settings.Default.Label2Text;
        string label3TextTemplate = Properties.Settings.Default.Label3Text;
        string label4TextTemplate = Properties.Settings.Default.Label4Text;
        int iSpace = Properties.Settings.Default.SpaceBetweenLabels;
        float label1Size = Properties.Settings.Default.Label1FontSize;
        float label2Size = Properties.Settings.Default.Label2FontSize;
        float label3Size = Properties.Settings.Default.Label3FontSize;
        float label4Size = Properties.Settings.Default.Label4FontSize;
        Color label1Colour = Color.FromName(Properties.Settings.Default.Label1FontColour);
        Color label2Colour = Color.FromName(Properties.Settings.Default.Label2FontColour);
        Color label3Colour = Color.FromName(Properties.Settings.Default.Label3FontColour);
        Color label4Colour = Color.FromName(Properties.Settings.Default.Label4FontColour);
        Color backgroundColour = Color.FromName(Properties.Settings.Default.BackgroundColour);
        float backgroundOpacity = int.Parse(Properties.Settings.Default.BackgroundOpacity.ToString());
        int iInterval = Properties.Settings.Default.Interval;
        bool fade = Properties.Settings.Default.Fade;
        bool dimLabels = Properties.Settings.Default.DimLabels;
        int dimLevel = Properties.Settings.Default.DimLevel;

        FadeType fadeDirection = FadeType.FadeIn;


        #region OnTop

        static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
        static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
        static readonly IntPtr HWND_TOP = new IntPtr(0);
        static readonly IntPtr HWND_BOTTOM = new IntPtr(1);
        const UInt32 SWP_NOSIZE = 0x0001;
        const UInt32 SWP_NOMOVE = 0x0002;
        const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        #endregion

        #region Preview API's

        [DllImport("user32.dll")]
        static extern IntPtr SetParent(IntPtr hWndChild, IntPtr hWndNewParent);

        [DllImport("user32.dll")]
        static extern int SetWindowLong(IntPtr hWnd, int nIndex, IntPtr dwNewLong);

        [DllImport("user32.dll", SetLastError = true)]
        static extern int GetWindowLong(IntPtr hWnd, int nIndex);

        [DllImport("user32.dll")]
        static extern bool GetClientRect(IntPtr hWnd, out Rectangle lpRect);

        #endregion

        #region Constructors

        public ScreensaverForm()
        {
            InitializeComponent();
        }

        //This constructor is passed the bounds this form is to show in
        //It is used when in normal mode
        public ScreensaverForm(Rectangle Bounds)
        {
            InitializeComponent();
            this.Bounds = Bounds;
            //hide the cursor
            Cursor.Hide();
        }

        //This constructor is the handle to the select screen saver dialog preview window
        //It is used when in preview mode (/p)
        public ScreensaverForm(IntPtr PreviewHandle)
        {
            InitializeComponent();

            //set the preview window as the parent of this window
            SetParent(this.Handle, PreviewHandle);

            //make this a child window, so when the select screensaver 
            //dialog closes, this will also close
            SetWindowLong(this.Handle, -16,
                  new IntPtr(GetWindowLong(this.Handle, -16) | 0x40000000));

            //set our window's size to the size of our window's new parent
            Rectangle ParentRect;
            GetClientRect(PreviewHandle, out ParentRect);
            this.Size = ParentRect.Size;

            //set our location at (0, 0)
            this.Location = new Point(0, 0);

            IsPreviewMode = true;
        }

        #endregion

        #region User Input

        private void ScreensaverForm_KeyDown(object sender, KeyEventArgs e)
        {
            //** take this if statement out if your not doing a preview
            if (!IsPreviewMode) //disable exit functions for preview
            {

                if (fade)
                { tmrFade.Enabled = true; }
                else
                { Application.Exit(); }
            }
        }

        private void ScreensaverForm_Click(object sender, EventArgs e)
        {
            //** take this if statement out if your not doing a preview
            if (!IsPreviewMode) //disable exit functions for preview
            {
                if (fade)
                { tmrFade.Enabled = true; }
                else
                { Application.Exit(); }
            }
        }

        //start off OriginalLoction with an X and Y of int.MaxValue, because
        //it is impossible for the cursor to be at that position. That way, we
        //know if this variable has been set yet.
        Point OriginalLocation = new Point(int.MaxValue, int.MaxValue);

        private void ScreensaverForm_MouseMove(object sender, MouseEventArgs e)
        {
            //** take this if statement out if your not doing a preview
            if (!IsPreviewMode) //disable exit functions for preview
            {
                //see if originallocation has been set
                if (OriginalLocation.X == int.MaxValue &
                    OriginalLocation.Y == int.MaxValue)
                {
                    OriginalLocation = e.Location;
                }
                //see if the mouse has moved more than 20 pixels 
                //in any direction. If it has, close the application.
                if (Math.Abs(e.X - OriginalLocation.X) > 20 |
                    Math.Abs(e.Y - OriginalLocation.Y) > 20)
                {
                    if (fade)
                    { tmrFade.Enabled = true; }
                    else
                    { Application.Exit(); }
                }
            }
        }
        #endregion

        private void timer1_Tick(object sender, EventArgs e)
        {

            string
                label1Text = label1TextTemplate,
                label2Text = label2TextTemplate,
                label3Text = label3TextTemplate,
                label4Text = label4TextTemplate;

            if (timer1.Interval != iInterval) timer1.Interval = iInterval;

            string pattern = @"[G][e][t][PM][ro][od][pe][eS][rt][ta][yt][Ve][alue]*[(]([A-Za-z0-9 ,]+?)[)]";

            Regex rgx = new Regex(pattern);
            MatchCollection result = rgx.Matches(label1Text + label2Text + label3Text + label4Text);

            foreach (Match match in result)
            {
                string newValue = "";
                string[] args = match.Value.Substring(match.Value.IndexOf(char.Parse("(")) + 1, match.Value.Length - ((match.Value.IndexOf(char.Parse("(")) + 2))).Split(char.Parse(","));

                // If GetPropertyValue
                if (match.Value.Contains("GetPropertyValue"))
                {
                    if (args.Length == 3) newValue = GetPropertyValue(args[0], args[1], args[2]);
                    else newValue = GetPropertyValue(args[0], args[1]);

                }
                // If GetModeState not working
                else
                {
                    newValue = GetModeState(args[0]);
                }

                label1Text = label1Text.Replace(match.Value, newValue);
                label2Text = label2Text.Replace(match.Value, newValue);
                label3Text = label3Text.Replace(match.Value, newValue);
                label4Text = label4Text.Replace(match.Value, newValue);

            }


            //Console.WriteLine("Original String:    '{0}'", input);
            //Console.WriteLine("Replacement String: '{0}'", result);

            if (label1.Text != label1Text) label1.Text = label1Text;
            if (label2.Text != label2Text) label2.Text = label2Text;
            if (label3.Text != label3Text) label3.Text = label3Text;
            if (label4.Text != label4Text) label4.Text = label4Text;

            label1.Left = (this.Width / 2) - (label1.Width / 2);
            label1.Top = (this.Height / 2)
                - (label1.Height / 2) - iSpace
                - (label2.Height / 2) - iSpace
                - (label3.Height / 2) - iSpace
                - (label4.Height / 2) - iSpace;

            label2.Left = (this.Width / 2) - (label2.Width / 2);
            label2.Top = (this.Height / 2)
                + (label1.Height / 2) + iSpace
                - (label2.Height / 2) - iSpace
                - (label3.Height / 2) - iSpace
                - (label4.Height / 2) - iSpace;

            label3.Left = (this.Width / 2) - (label3.Width / 2);
            label3.Top = (this.Height / 2)
                + (label1.Height / 2) + iSpace
                + (label2.Height / 2) + iSpace
                - (label3.Height / 2) - iSpace
                - (label4.Height / 2) - iSpace;

            label4.Left = (this.Width / 2) - (label4.Width / 2);
            label4.Top = (this.Height / 2)
                + (label1.Height / 2) + iSpace
                + (label2.Height / 2) + iSpace
                + (label3.Height / 2) + iSpace
                - (label4.Height / 2) - iSpace;


            //dim labels if selected
            if (dimLabels)
            {
                if (GetPropertyValue("System Time", "Sunrise Indicator") == "0")
                {
                    //Console.Beep();
                    label1.ForeColor = DarkenColor(label1Colour);
                    label2.ForeColor = DarkenColor(label2Colour);
                    label3.ForeColor = DarkenColor(label3Colour);
                    label4.ForeColor = DarkenColor(label4Colour);
                }
                else
                {

                    label1.ForeColor = label1Colour;
                    label2.ForeColor = label2Colour;
                    label3.ForeColor = label3Colour;
                    label4.ForeColor = label4Colour;
                }

            }
        }

        public Color DarkenColor(Color color)
        {
            int decrease = dimLevel;

            int r = Math.Max(Convert.ToInt32(color.R) - decrease, 0);
            int g = Math.Max(Convert.ToInt32(color.G) - decrease, 0);
            int b = Math.Max(Convert.ToInt32(color.B) - decrease, 0);
            return Color.FromArgb(r, g, b);
        }

        #region Housebot Methods

        // This function will display device values from housebot
        public string GetPropertyValue(string device_name, string property_name)
        {
            try
            {
                if (hb == null) Connect();
                string newValue = "";
                string response = "";
                for (int r = 0; r < RETRY; r++)
                {
                    //get value from housebot
                    newValue = hb.GetPropertyValue(device_name, property_name);

                    //check that there is not an error
                    if (!newValue.Equals("**Error**"))
                    {
                        //looks ok, so returning housebot value
                        return newValue;
                    }
                    else
                    {
                        //there is a problem, so attempts to connect first
                        response = Connect();
                    }
                }
                //still can not connect, so return response message
                return "**Error: " + response;
            }
            catch (Exception ex)
            {
                return "**Error: " + ex.Message;
            }
        }

        // This function will display mode state from housebot
        public string GetModeState(string mode_name)
        {
            try
            {
                if (hb == null) Connect();
                string newValue = "";
                string response = "";
                for (int r = 0; r < RETRY; r++)
                {
                    //get value from housebot
                    newValue = hb.GetModeState(mode_name);

                    //check that there is not an error
                    if (!newValue.Equals("**Error**"))
                    {
                        //looks ok, so returning housebot value
                        return newValue;
                    }
                    else
                    {
                        //there is a problem, so attempts to connect first
                        response = Connect();
                    }
                }
                //still can not connect, so return response message
                return "**Error: " + response;
            }
            catch (Exception ex)
            {
                return "**Error: " + ex.Message;
            }
        }

        // This function will display device alpha list values from housebot
        public string GetPropertyValue(string device_name, string property_name, string linenumber)
        {
            try
            {
                if (hb == null) Connect();
                string newValue = "";
                string response = "";
                for (int r = 0; r < RETRY; r++)
                {
                    //get value from housebot
                    newValue = hb.GetPropertyValue(device_name, property_name);

                    //check that there is not an error
                    if (!newValue.Equals("**Error**"))
                    {
                        //looks ok, so returning housebot value
                        if (newValue.Contains("\n"))
                        {
                            string[] lines = newValue.Split(char.Parse("\n"));
                            return lines[int.Parse(linenumber) - 1];
                        }
                        else
                        {
                            return newValue;
                        }
                    }
                    else
                    {
                        //there is a problem, so attempts to connect first
                        response = Connect();
                    }
                }
                //still can not connect, so return response message
                return "**Error: " + response;
            }
            catch (Exception ex)
            {
                return "**Error: " + ex.Message;
            }

        }

        private string Connect()
        {
            try
            {
                //disconnect all connection first
                hb = null;

                //declaire new connection and connect
                hb = new HBControl();
                string response = hb.Connect(hbPort, hbHost, hbPassword);
                if (response == null)
                    return "Unable to connect to HouseBot";
                else
                    return response;
            }
            catch (Exception ex)
            {
                return ex.Message;
            }
        }

        #endregion

        private void ScreensaverForm_Load(object sender, EventArgs e)
        {
            Cursor.Hide();
            this.BackColor = backgroundColour;
            this.Opacity = 0;// backgroundOpacity / 100; 
            label1.Font = new Font(FontFamily.GenericSansSerif, label1Size);
            label2.Font = new Font(FontFamily.GenericSansSerif, label2Size);
            label3.Font = new Font(FontFamily.GenericSansSerif, label3Size);
            label4.Font = new Font(FontFamily.GenericSansSerif, label4Size);
            label1.ForeColor = label1Colour;
            label2.ForeColor = label2Colour;
            label3.ForeColor = label3Colour;
            label4.ForeColor = label4Colour;

            SystemEvents.DisplaySettingsChanged += new EventHandler(SystemEvents_DisplaySettingsChanged);

            //set always ontop
            SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);


            if (fade)
            { tmrFade.Enabled = true; }
            else
            { this.Opacity = backgroundOpacity / 100; }

        }

        void SystemEvents_DisplaySettingsChanged(object sender, EventArgs e)
        {
            //display has chnaged so restart
            Application.Restart();
        }

        private void tmrFade_Tick(object sender, EventArgs e)
        {
            //if fade enabled then start fading
            //if (fade)
            //{

            if (fadeDirection == FadeType.FadeIn)
            {
                if (this.Opacity <= backgroundOpacity / 100)
                {
                    this.Opacity = this.Opacity + 0.01;
                }
                else
                {
                    tmrFade.Enabled = false;
                    tmrFade.Interval = 10;
                    fadeDirection = FadeType.FadeOut;
                }
            }
            else
            {

                if (this.Opacity > 0)
                {
                    this.Opacity = this.Opacity - 0.05;
                }
                else
                {
                    tmrFade.Enabled = false;
                    Application.Exit();
                }

            }

        }

        //// fade disabled 
        //else
        //{
        //    if (this.Opacity == 0)
        //    {
        //        this.Opacity = backgroundOpacity / 100;
        //        tmrFade.Enabled = false;
        //    }
        //    else
        //    {
        //        Application.Exit();
        //    }

        //}




    }
}

